/**********************************************************
**   PARSER_C.FRM
**   Coco/R C Support Frames.
**   Author: Frankie Arzu <farzu@uvg.edu.gt>
**
**   Jun 12, 1996   Version 1.06
**      Many fixes and suggestions thanks to
**      Pat Terry <p.terry@ru.ac.za>
**********************************************************/

#include "alvos.hpp"
#include "alvop.hpp"

#include "alvopp.hxx"

extern AlvoPP psr;
/* void** */

ALVO*alvo_closure;

/*--------------------------------------------------------------------------*/



Error_Func Custom_Error = 0L;

static Syms Sym;
static int errors = 0;                /*number of detected errors*/
static int ErrDist = MinErrDist;

#define MAXSYM		1


/* Production prototypes */

static void alvo(void);
static void Alvo(void);
static void Expr(void);
static void Factor(void);
static void Eval(void);


#define NSETBITS        16

static unsigned short int SymSet[][MAXSYM] = {
  /*EOF_Sym */
  {0x1},
  {0x0}
};

void GenError(int a_errno)
{ if (ErrDist >= MinErrDist) {
    if (Custom_Error != 0L)
      (*Custom_Error) (a_errno, S_NextLine, S_NextCol, S_NextPos);
    errors++;
  }
  ErrDist = 0;
}

void SynError(int a_errno)
{ if (a_errno <= MAXERROR) a_errno = MAXERROR;
  if (ErrDist >= MinErrDist) {
    if (Custom_Error != 0L)
      (*Custom_Error) (a_errno, S_NextLine, S_NextCol, S_NextPos);
    errors++;
  }
  ErrDist = 0;
}

void SemError(int a_errno)
{ if (a_errno <= MAXERROR) a_errno = MAXERROR;
  if (ErrDist >= MinErrDist) {
    if (Custom_Error != 0L)
      (*Custom_Error) (a_errno, S_Line, S_Col, S_Pos);
    errors++;
  }
  ErrDist = 0;
}

static void Get(void)
{ do {
    Sym = S_Get();
    if (Sym <= MAXT) ErrDist ++;
    else {
      /* Empty Stmt */ ;
      S_NextPos  = S_Pos;  S_NextCol = S_Col;
      S_NextLine = S_Line; S_NextLen = S_Len;
    }
  } while (Sym > MAXT);
}

static int In (unsigned short int *SymbolSet, int i)
{ return SymbolSet[i / NSETBITS] & (1 << (i % NSETBITS)); }

static void Expect (Syms n)
{ if (Sym == n) Get(); else GenError(n); }

static void ExpectWeak (Syms aSymbol, int follow)
{ if (Sym == aSymbol) Get();
  else {
    GenError(aSymbol);
    while (!(In(SymSet[follow], Sym) || In(SymSet[0], Sym))) Get();
  }
}

static int WeakSeparator (Syms aSymbol, int syFol, int repFol)
{ unsigned short int s[MAXSYM];
  int i;

  if (Sym == aSymbol) { Get(); return 1; }
  if (In(SymSet[repFol], Sym)) return 0;
  for (i = 0; i < MAXSYM; i++)
    s[i] = SymSet[0][i] | SymSet[syFol][i] | SymSet[repFol][i];
  GenError(aSymbol);
  while (!In(s, Sym)) Get();
  return In(SymSet[syFol], Sym);
}

int Successful(void)
{ return errors == 0; }

/* Productions */

static void alvo(void)
{
	Alvo();
	// * alvo_closure=psr.Result;/*closure=psr.Result;*/;
	//alvo_closure=(ALVO*)psr.Result; //TODO 
	//alvo_closure.save (psr.Result)'
}
static void Alvo(void)
{
	while (Sym >= symbolSym && Sym <= numericSym ||
	       Sym >= stringSym && Sym <= LparenSym ||
	       Sym == LbrackSym ||
	       Sym == LbraceSym ||
	       Sym == SlashSym) {
		Expr();
	}
}

static void Expr(void)
{
	switch (Sym) {
		case LparenSym:  
			Get();
			psr.sg();
			while (Sym >= symbolSym && Sym <= numericSym ||
			       Sym >= stringSym && Sym <= LparenSym ||
			       Sym == LbrackSym ||
			       Sym == LbraceSym ||
			       Sym == SlashSym) {
				Expr();
			}
			Expect(RparenSym);
			psr.eg();
			break;
		case LbrackSym:  
			Get();
			psr.sl();
			while (Sym >= symbolSym && Sym <= numericSym ||
			       Sym >= stringSym && Sym <= LparenSym ||
			       Sym == LbrackSym ||
			       Sym == LbraceSym ||
			       Sym == SlashSym) {
				Expr();
			}
			Expect(RbrackSym);
			psr.el();
			break;
		case LbraceSym:  
			Get();
			psr.sz();
			while (Sym >= symbolSym && Sym <= numericSym ||
			       Sym >= stringSym && Sym <= LparenSym ||
			       Sym == LbrackSym ||
			       Sym == LbraceSym ||
			       Sym == SlashSym) {
				Expr();
			}
			Expect(RbraceSym);
			psr.ez();
			break;
		case EOF_Sym: 
		case symbolSym: 
		case numericSym: 
		case stringSym: 
		case RparenSym: 
		case RbrackSym: 
		case RbraceSym: 
		case SlashSym:  
			while (Sym >= symbolSym && Sym <= numericSym ||
			       Sym == stringSym ||
			       Sym == SlashSym) {
				Factor();
			}
			break;
		default :GenError(13); break;
	}
}

static void Factor(void)
{
	switch (Sym) {
		case SlashSym:  
			Eval();
			break;
		case stringSym:  
			Get();
			psr.stringular();
			break;
		case symbolSym:  
			Get();
			psr.symbol();
			break;
		case numericSym:  
			Get();
			psr.numeric();
			break;
		default :GenError(14); break;
	}
}

static void Eval(void)
{
	Expect(SlashSym);
	psr.eval();
	Expect(symbolSym);
	psr.symbol();
}



void Parse(void*closure)
{ 
	S_Reset(); Get();
	alvo_closure=/*(void*)*/(ALVO*)closure;
  alvo(/*closure*/);
}

